package com.xz.xzutils.utils;

import com.xz.xzutils.utils.dto.SqlDTO;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 *
 * </p>
 *
 * @author DONG.WANG17@HAND-CHINA.COM
 * @since 2025-01-03 16:16
 */
public class SqlParser {
    private static final String SQL_PREFIX = "Preparing:";
    private static final String PARAM_PREFIX = "Parameters:";
    private static final String PLACEHOLDERS = "?";

    public static List<SqlDTO> parse(String logText) {
        String[] logLines = logText.split("\n");
        List<SqlDTO> sqlList = new ArrayList<>();
        for (int i = 0; i < logLines.length; i++) {
            if (logLines[i].contains(SQL_PREFIX)) {
                SqlDTO sqlDTO = new SqlDTO();
                sqlDTO.setParseSuccess(true);
                sqlDTO.setSqlKey(parseSqlKey(logLines[i]));

                String templateSql = extractTemplateSql(logLines[i]);
                String parameters = null;
                if (i + 1 < logLines.length && logLines[i + 1].contains(PARAM_PREFIX)) {
                    parameters = extractParameters(logLines[i + 1]);
                    i = i + 2;
                }
                sqlDTO.setTemplateSql(blankToNull(templateSql));
                sqlDTO.setParameters(blankToNull(parameters));
                try {
                    sqlDTO.setSql(joinSql(templateSql, parameters));
                } catch (Exception e) {
                    sqlDTO.setParseSuccess(false);
                    sqlDTO.setMessage(e.getMessage());
                }
                sqlList.add(sqlDTO);
            } else if (logLines[i].contains(PARAM_PREFIX)) {
                // note：不做解析
                System.out.println("doNothing");
            }
        }
        return sqlList;
    }

    public static void parseLine(@NotNull String line,SqlDTO sqlDTO) {
        sqlDTO.setParseSuccess(true);
        if (line.contains(SQL_PREFIX)) {
            sqlDTO.setSqlKey(parseSqlKey(line));
            sqlDTO.setTemplateSql(extractTemplateSql(line));
            if(line.contains(PLACEHOLDERS)){
                sqlDTO.setNeedParameters(true);
            }else {
                sqlDTO.setNeedParameters(false);
                sqlDTO.setSql(extractTemplateSql(line));
            }
        }
        if(line.contains(PARAM_PREFIX)){
            sqlDTO.setParameters(extractParameters(line));
            sqlDTO.setNeedParameters(false);
            try {
                sqlDTO.setSql(joinSql(sqlDTO.getTemplateSql(), sqlDTO.getParameters()));
            } catch (Exception e) {
                sqlDTO.setParseSuccess(false);
                sqlDTO.setMessage(e.getMessage());
            }
        }
    }

    private static String blankToNull(String string) {
        return StringUtils.isBlank(string) ? null : string;
    }

    private static String extractTemplateSql(String line) {
        if (StringUtils.isBlank(line) && line.contains(SQL_PREFIX)) {
            return null;
        }
        String[] parts = line.split(SQL_PREFIX);
        return parts.length > 1 ? parts[1].trim() : null;
    }

    private static String extractParameters(String line) {
        if (StringUtils.isBlank(line) && line.contains(PARAM_PREFIX)) {
            return null;
        }
        String[] parts = line.split(PARAM_PREFIX);
        return parts.length > 1 ? parts[1].trim() : null;
    }


    // 拼接sql
    private static String joinSql(String templateSql,String parameters) throws Exception {
        if (StringUtils.isBlank(templateSql) && StringUtils.isBlank(parameters)) {
            throw new Exception(String.format("当前解析:\t[%s]和[%s]皆为空", SQL_PREFIX, PARAM_PREFIX));
        } else if (StringUtils.isBlank(templateSql) && StringUtils.isNotBlank(parameters)) {
            throw new Exception(String.format("当前解析:\t[%s]为空,但[%s]不为空", SQL_PREFIX, PARAM_PREFIX));
        } else if (StringUtils.isNotBlank(templateSql) && StringUtils.isBlank(parameters)) {
            if (templateSql.contains("?")) {
                // 模板sql中包含?的个数
                int questionMarkCount = StringUtils.countMatches(templateSql, "?");
                throw new Exception(String.format("当前解析:\t[%s]应为[%s]个参数,但[%s]为空", SQL_PREFIX, questionMarkCount, PARAM_PREFIX));
            } else {
                return templateSql;
            }
        } else {
            String[] sqlArr = preProcessSql(templateSql);
            String[] paramArr = preProcessParameters(parameters);
            int questionMarkCount = StringUtils.countMatches(templateSql, "?");
            if (questionMarkCount != paramArr.length) {
                throw new Exception(String.format("当前解析:\t[%s]所需参数为[%s]个,但[%s]包含参数为[%s]个", SQL_PREFIX, questionMarkCount, PARAM_PREFIX, paramArr.length));
            }
            StringBuilder resultSql = new StringBuilder();
            for (int i = 0; i < paramArr.length; i++) {
                resultSql.append(sqlArr[i]);
                resultSql.append(paramArr[i]);
            }
            if (paramArr.length < sqlArr.length) {
                resultSql.append(sqlArr[sqlArr.length - 1]);
            }
            return resultSql.toString();
        }
    }

    // 预处理sql
    private static String[] preProcessSql(String templateSql) {
        // TODO 不够准确，如果sql中写死一些数据 如 filed = "xxxx?xxx", 分割就会出错
        // 这里可以参照拦截器模块修改
        return templateSql.split("\\?");
    }

    // 预处理参数
    private static String[] preProcessParameters(String parameters) {
        if (StringUtils.isBlank(parameters)) {
            return new String[]{};
        }
        String[] paramArr = parameters.trim().split(",");
        for (int i = 0; i < paramArr.length; i++) {
            paramArr[i] = paramArr[i].trim();
            if ("null".equals(paramArr[i])) {
                // 为 null 直接返回
                continue;
            }
            // 格式 aaa(bbb)
            String regex = "(.+)\\((String|Timestamp|Integer|Long|Float|Double|BigDecimal|Boolean)\\)";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(paramArr[i]);
            if (matcher.matches()) {
                String value = matcher.group(1);
                String type = matcher.group(2);
                // 获取类型
                switch (type) {
                    case "String", "Timestamp", "Date", "Time", "LocalDate", "LocalTime", "LocalDateTime":
                        paramArr[i] = "'" + value + "'";
                        break;
                    case "Integer", "Long", "Float", "Double", "BigDecimal", "Boolean":
                        paramArr[i] = value;
                        break;
                    default:
                        throw new RuntimeException(String.format("不支持的参数类型:\t[%s]", type));
                }
            } else {
                throw new RuntimeException(String.format("参数格式错误,支持格式为:\tvalue(String|Timestamp|Date|Time|LocalDate|LocalTime|LocalDateTime|Integer|Long|Float|Double|BigDecimal|Boolean) \t当前格式为:\t[%s]", paramArr[i]));
            }
        }
        return paramArr;
    }

    // 获取当前时间格式化后时间字符串
    private static String getFormatDate() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    private static String parseSqlKey(String logLine) {
        if (StringUtils.isBlank(logLine) || !logLine.contains(SQL_PREFIX)) {
            return String.format("-- [Xz Sql Parser]-[%s]-[%s]", getFormatDate(), UUID.randomUUID());
        }
        String sqlKey = logLine.split(SQL_PREFIX)[0].trim();
        return String.format("-- [%s]-[%s]", sqlKey, UUID.randomUUID());
    }
}
